/**
 * @author 		chenc
 * @version 	1.0
 * @date 		2016.6.16
 *
 * @file 		sct/mux/tsmux.h
 * @brief 		ts mux interface
 *
 * CTSMux
 */

#ifndef SCT_MUX_TSMUX_H
#define SCT_MUX_TSMUX_H

#include "sct/core/common.h"
#include "sct/core/mutex.h"

#define SCT_TS_PACKET_SIZE 188

namespace sct
{

class CTSMux;
class CTsMuxCallback
{
	friend class CTSMux;
public:
	virtual ~CTsMuxCallback(){}

protected:
	virtual void onTsPacketBuilded(CTSMux*caller, const void * p) {}
};

class CTSMux
{
public:
	enum StreamType
	{
		ST_H264 = 1,
		ST_AAC,
		ST_End,
	};

public:
	class CStreamInfo
	{
	public:
		int type;///not StreamType
		int id;

		int pid;
		int cnt;
	};
	class CProgramInfo
	{
	public:
		int program;

		int pcr_pid;
		int pcr_cnt;

		int pid;
		int cnt;
		std::list<CStreamInfo*> streams;
	};

public:
	/**
	 * each object means a MPEG-2 TS stream
	 */
	CTSMux(const int id);
	~CTSMux();

	CProgramInfo* createProgram(const int program);
	CStreamInfo* createStream(CProgramInfo* program, const StreamType type);
	void init();

	/**
	 * create one pat packet (in one ts packet)
	 *
	 * call this function interval should less than 0.5s
	 */
	void buildPATPacket();
	/**
	 * create one pmt packet (in one ts packet)
	 *
	 * call this function interval should less than 0.5s
	 */
	void buildPMTPacket();
	/**
	 * create one null packet (in one ts packet)
	 *
	 * just for keep the bitrate stable
	 */
	void buildNULLPacket();

	/**
	 * create one pcr packet (in one ts packet)
	 *
	 * call this function interval should less than 0.1s
	 *
	 * @param pcr ,the clock is 90000Hz
	 */
	void buildPCRPacket(CProgramInfo* program, const int64_t pcr);

	/**
	 * make es stream to pes packet
	 *
	 * @param pts present timestamp of the es, the clock is 90000Hz
	 * @param dts decode timespace of the es, the clock is 90000Hz
	 * @param pid the es belong to.
	 */
	void buildPESPacket(CStreamInfo*stream, const void * p, const int len,
			const int64_t pts,
			const int64_t dts);


	void addCallback(CTsMuxCallback * inst) {mCallBack = inst;}
	void delCallback(CTsMuxCallback * inst) {mCallBack = NULL;}

    static CTSMux::StreamType getStreamType(const int tsStreamType);
private:
	/**
	 * put one ts packet to the output
	 */
	void putTSPacket(const void * p);

	/**
	* write pts or dts to ts stream
	*
	* @param p, the pointer of curren buffer index
	* @param fb, (1)both pts and dts, for pts value is 3, for dts value is 1;(2)only pts, the value is 2
	* @param pts, pts or dts
	* @return p
	*/
	uint8_t *writePts(uint8_t *p, const  int fb, const int64_t pts);

	void _buildPMTPacket(CProgramInfo * program);
private:
	std::list<CProgramInfo *> mPrograms;
	int mPATCnt;
	int mNullCnt;
	int mTsStreamId;

	CTsMuxCallback * mCallBack;
};

}//end namespace

#endif
